﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Collections;
using System.IO;
using System.IO.Compression;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.Serialization.Formatters.Binary;
using Newtonsoft.Json;

namespace JFLogic.Utils
{
    public class HttpUtils
    {
        public string sid { get; set; }

        string cachePath = System.Configuration.ConfigurationManager.AppSettings["BasePath"] + "cache\\";

        string cacheFullName;

        public HttpUtils(string _sid)
        {
            if (!Directory.Exists(cachePath))
            {
                Directory.CreateDirectory(cachePath);
            }

            cachePath = cachePath + DateTime.Now.ToString("yyyyMMdd") + "\\";
            if (!Directory.Exists(cachePath))
            {
                Directory.CreateDirectory(cachePath);    
            }
            

            sid = _sid;
            
            cacheFullName = cachePath + _sid;
        }


        private const string DefaultUserAgent = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1";  

        

        private void BugFix_CookieDomain(CookieContainer cookieContainer)
        {
            System.Type _ContainerType = typeof(CookieContainer);
            Hashtable table = (Hashtable)_ContainerType.InvokeMember("m_domainTable",
                                       System.Reflection.BindingFlags.NonPublic |
                                       System.Reflection.BindingFlags.GetField |
                                       System.Reflection.BindingFlags.Instance,
                                       null,
                                       cookieContainer,
                                       new object[] { });
            ArrayList keys = new ArrayList(table.Keys);
            foreach (string keyObj in keys)
            {
                string key = (keyObj as string);
                if (key[0] == '.')
                {
                    string newKey = key.Remove(0, 1);
                    table[newKey] = table[keyObj];
                }
            }
        }

        private String GetMid(String input, String s, String e)
        {
            int pos = input.IndexOf(s);
            if (pos == -1)
            {
                return "";
            }


            pos += s.Length;


            int pos_end = 0;
            if (e == "")
            {
                pos_end = input.Length;
            }
            else
            {
                pos_end = input.IndexOf(e, pos);
            }


            if (pos_end == -1)
            {
                return "";
            }


            return input.Substring(pos, pos_end - pos);
        }

        /// <summary>
        /// 下载网络图片
        /// </summary>
        /// <param name="url"></param>
        /// <param name="path"></param>
        /// <param name="fileName"></param>
        /// <param name="referer"></param>
        /// <returns></returns>
        public bool Download(string url, string path, string fileName, string referer)
        {
            bool suc = false;
            string savePath = path + fileName;
            StreamReader reader = null;
            HttpWebRequest webReqst = null;
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                webReqst = WebRequest.Create(url) as HttpWebRequest;
                webReqst.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                webReqst = WebRequest.Create(url) as HttpWebRequest;
            }
            Stream stream = null;
            HttpWebResponse webResponse = null;
            CookieContainer CC = ReadCookiesFromDisk();
            try
            {
                if (!string.IsNullOrEmpty(referer))
                {
                    webReqst.Referer = referer;
                }
                
                webReqst.Method = "GET";
                webReqst.UserAgent = DefaultUserAgent;
                webReqst.KeepAlive = false;
                
                webReqst.CookieContainer = CC;
                webReqst.Timeout = 30000;
                webReqst.ReadWriteTimeout = 30000;
                webReqst.ContentType = "text/html; charset=utf-8";

                webResponse = (HttpWebResponse)webReqst.GetResponse();
                BugFix_CookieDomain(CC);
                if (webResponse.StatusCode == HttpStatusCode.OK)
                {
                    using (Stream sream = webResponse.GetResponseStream())
                    {
                        List<byte> list = new List<byte>();
                        while (true)
                        {
                            int data = sream.ReadByte();
                            if (data == -1)
                                break;
                            list.Add((byte)data);
                        }
                        File.WriteAllBytes(savePath, list.ToArray());
                    }
                    suc = true;
                }
            }
            catch (Exception ex)
            {
                string strEx = "";
                strEx = string.Format("doget Exception:{1},{0}", ex.StackTrace, ex.Message.ToString());
                System.Threading.Thread.Sleep(3000);
                Log.PrintLog(strEx);
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                    reader = null;
                }
                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }
                if (webResponse != null)
                {
                    webResponse.Close();
                    webResponse = null;
                }
                if (webReqst != null)
                {
                    webReqst.Abort();
                    webReqst = null;
                }
            }

            WriteCookiesToDisk( CC);

            return suc;
        }

        public String DoGet(String url, string referer)
        {
            String html = "";
            StreamReader reader = null;
            HttpWebRequest webReqst = null;
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                webReqst = WebRequest.Create(url) as HttpWebRequest;
                webReqst.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                webReqst = WebRequest.Create(url) as HttpWebRequest;
            }
            Stream stream = null;
            HttpWebResponse webResponse = null;
            CookieContainer CC = ReadCookiesFromDisk();
            try
            {
                if (!string.IsNullOrEmpty(referer))
                {
                    webReqst.Referer = referer;
                }

                webReqst.Method = "GET";
                webReqst.UserAgent = DefaultUserAgent;
                webReqst.KeepAlive = false;
                webReqst.CookieContainer = CC;
                webReqst.Timeout = 30000;
                webReqst.ReadWriteTimeout = 30000;
                webReqst.ContentType = "text/html; charset=utf-8";

                webResponse = (HttpWebResponse)webReqst.GetResponse();
                BugFix_CookieDomain(CC);
                if (webResponse.StatusCode == HttpStatusCode.OK && webResponse.ContentLength < 1024 * 1024)
                {
                    stream = webResponse.GetResponseStream();
                    stream.ReadTimeout = 30000;
                    if (webResponse.ContentEncoding == "gzip")
                    {
                        reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress), Encoding.Default);
                    }
                    else
                    {
                        reader = new StreamReader(stream, Encoding.UTF8);
                    }
                    html = reader.ReadToEnd();
                }
            }
            catch(Exception ex)
            {
                string strEx = "";
                strEx = string.Format("doget Exception:{1},{0}", ex.StackTrace, ex.Message.ToString());
                System.Threading.Thread.Sleep(3000);
                Log.PrintLog(strEx);
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                    reader = null;
                }
                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }
                if (webResponse != null)
                {
                    webResponse.Close();
                    webResponse = null;
                }
                if (webReqst != null)
                {
                    webReqst.Abort();
                    webReqst = null;
                }
            }

            WriteCookiesToDisk( CC);

            return html;
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受    
        }

        public String DoPost(String url, String Content, string referer)
        {
            return DoPost(url, Content, referer, null);
        }

        public String DoPost(String url, String Content, string referer, WebHeaderCollection headers)
        {
            string html = "";
            StreamReader reader = null;
            HttpWebRequest webReqst = null;
            Stream stream = null;
            HttpWebResponse webResponse = null;
            //如果是发送HTTPS请求    
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                webReqst = WebRequest.Create(url) as HttpWebRequest;
                webReqst.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                webReqst = WebRequest.Create(url) as HttpWebRequest;
            }

            if (!string.IsNullOrEmpty(referer))
            {
                webReqst.Referer = referer;
            }
            if (headers != null)
            {
                webReqst.Headers.Add(headers);    
            }
            CookieContainer CC = ReadCookiesFromDisk();
            
            // Set some reasonable limits on resources used by this request
            webReqst.MaximumAutomaticRedirections = 4;
            webReqst.MaximumResponseHeadersLength = 4;
            // Set credentials to use for this request.
            webReqst.Credentials = CredentialCache.DefaultCredentials;
            webReqst.Method = "POST";
            webReqst.UserAgent = DefaultUserAgent;
            webReqst.ContentType = "application/x-www-form-urlencoded";
            webReqst.KeepAlive = false;
            webReqst.CookieContainer = CC;
            webReqst.Timeout = 30000;
            webReqst.ReadWriteTimeout = 30000;
            try
            {
                if (Content == null)
                {
                    Content = "";
                }
                byte[] data = Encoding.UTF8.GetBytes(Content);
                webReqst.ContentLength = data.Length;
                stream = webReqst.GetRequestStream();
                stream.Write(data, 0, data.Length);
                

                
                webResponse = (HttpWebResponse)webReqst.GetResponse();
                BugFix_CookieDomain(CC);
                if (webResponse.StatusCode == HttpStatusCode.OK && webResponse.ContentLength < 1024 * 1024)
                {
                    stream = webResponse.GetResponseStream();
                    stream.ReadTimeout = 30000;
                    if (webResponse.ContentEncoding == "gzip")
                    {
                        reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress), Encoding.UTF8);
                    }
                    else
                    {
                        reader = new StreamReader(stream, Encoding.UTF8);
                    }
                    html = reader.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                string strEx = "";
                strEx = string.Format("sendhttp Exception:{1},{0}", ex.StackTrace, ex.Message.ToString());
                System.Threading.Thread.Sleep(3000);
                Log.PrintLog(strEx);
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                    reader = null;
                }
                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }
                if (webResponse != null)
                {
                    try
                    {
                        webResponse.Close();
                        webResponse = null;
                    }
                    catch
                    {
                        ;
                    }
                }
                if (webReqst != null)
                {
                    webReqst.Abort();
                    webReqst = null;
                }
                

            }

            WriteCookiesToDisk(CC);

            return html;
        }

        public static string RunJavascript(string js)
        {

            MSScriptControl.ScriptControlClass sc = new MSScriptControl.ScriptControlClass();
            sc.Language = "javascript";
            object obj = sc.Eval(js);
            return obj.ToString();
        }


        public void WriteCookiesToDisk( CookieContainer cookieJar)
        {


            using (Stream stream = File.Create(cacheFullName))
            {
                try
                {
                    //Log.PrintLog("Writing cookies to disk... ");
                    BinaryFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, cookieJar);
                    //Log.PrintLog("Done.");
                }
                catch (Exception e)
                {
                    Log.PrintLog("Problem writing cookies to disk: " + e.GetType());
                }
            }
        }

        public CookieContainer ReadCookiesFromDisk()
        {
            
            try
            {
                if (File.Exists(cacheFullName))
                {
                    using (Stream stream = File.Open(cacheFullName, FileMode.Open))
                    {
                        //Log.PrintLog("Reading cookies from disk... ");
                        BinaryFormatter formatter = new BinaryFormatter();
                        //Log.PrintLog("Done.");
                        return (CookieContainer)formatter.Deserialize(stream);
                    }
                }
                else 
                {
                    return new CookieContainer();
                }
                
            }
            catch (Exception e)
            {
                Log.PrintLog("Problem reading cookies from disk: " + e.GetType());
                return new CookieContainer();
            }
        }


        public List<Cookie> GetAllCookies(CookieContainer cc)
        {
            List<Cookie> lstCookies = new List<Cookie>();

            Hashtable table = (Hashtable)cc.GetType().InvokeMember("m_domainTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, cc, new object[] { });
            StringBuilder sb = new StringBuilder();
            foreach (object pathList in table.Values)
            {
                SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, pathList, new object[] { });
                foreach (CookieCollection colCookies in lstCookieCol.Values)
                    foreach (Cookie c in colCookies)
                    {
                        lstCookies.Add(c);
                        
                        sb.AppendLine(JsonConvert.SerializeObject(c));
                    }
            }
            Log.PrintLog(sb.ToString());
            return lstCookies;
        }


    }
}
